home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / ARP.C < prev    next >
C/C++ Source or Header  |  1990-01-01  |  10KB  |  356 lines

  1. /* Address Resolution Protocol (ARP) functions. Sits between IP and
  2.  * Level 2, mapping IP to Level 2 addresses for all outgoing datagrams.
  3.  */
  4. #include "global.h"
  5. #include "mbuf.h"
  6. #include "timer.h"
  7. #include "iface.h"
  8. #include "enet.h"
  9. #include "ax25.h"
  10. #include "arp.h"
  11.  
  12. extern int32 ip_addr;        /* Our IP address */
  13.  
  14. /* ARP entries for particular subnetwork types. The table values
  15.  * are filled in by calls to arp_init() at device attach time
  16.  */
  17. extern struct arp_type arp_type[];
  18.  
  19. /* Hash table headers */
  20. struct arp_tab *arp_tab[ARPSIZE];
  21.  
  22. struct arp_stat arp_stat;
  23.  
  24. /* Initialize an entry in the ARP table
  25.  * Called by the device driver at attach time
  26.  */
  27. arp_init(hwtype,hwalen,iptype,arptype,bdcst,format,scan)
  28. unsigned int hwtype;    /* ARP Hardware type */
  29. int hwalen;        /* Hardware address length */
  30. int iptype;        /* Subnet's protocol ID for IP */
  31. int arptype;        /* Subnet's protocol ID for ARP */
  32. char *bdcst;        /* Subnet's broadcast address (if any) */
  33. int (*format)();    /* Function to format hardware addresses */
  34. int (*scan)();        /* Function to scan addresses in ascii */
  35. {
  36.     register struct arp_type *at;
  37.  
  38.     if(hwtype >= NHWTYPES)
  39.         return -1;    /* Table too small */
  40.  
  41.     at = &arp_type[hwtype];
  42.     at->hwalen = (int16)hwalen;
  43.     at->iptype = (int16)iptype;
  44.     at->arptype = (int16)arptype;
  45.     at->bdcst = bdcst;
  46.     at->format = format;
  47.     at->scan = scan;
  48.     return 0;
  49. }
  50.  
  51. /* Resolve an IP address to a hardware address; if not found,
  52.  * initiate query and return NULLCHAR.    If an address is returned, the
  53.  * interface driver may send the packet; if NULLCHAR is returned,
  54.  * res_arp() will have saved the packet on its pending queue,
  55.  * so no further action (like freeing the packet) is necessary.
  56.  */
  57. char *
  58. res_arp(interface,hardware,target,bp)
  59. struct interface *interface;    /* Pointer to interface block */
  60. int16 hardware;        /* Hardware type */
  61. int32 target;        /* Target IP address */
  62. struct mbuf *bp;    /* IP datagram to be queued if unresolved */
  63. {
  64.     void arp_output();
  65.     register struct arp_tab *arp;
  66.  
  67.     if((arp = arp_lookup(interface,hardware,target)) != NULLARP && arp->state == ARP_VALID)
  68.         return arp->hw_addr;
  69.     /* Create an entry and put the datagram on the
  70.      * queue pending an answer. When no memory, drop the datagram
  71.      */
  72.     if ((arp = arp_add(interface,target,hardware,NULLCHAR,0,0)) == NULLARP){
  73.         free_p(bp);
  74.     } else {
  75.         enqueue(&arp->pending,bp);
  76.         arp_output(interface,hardware,target);
  77.     }
  78.     return NULLCHAR;
  79. }
  80. /* Handle incoming ARP packets. This is almost a direct implementation of
  81.  * the algorithm on page 5 of RFC 826, except for:
  82.  * 1. Outgoing datagrams to unresolved addresses are kept on a queue
  83.  *    pending a reply to our ARP request.
  84.  * 2. The names of the fields in the ARP packet were made more mnemonic.
  85.  * 3. Requests for IP addresses listed in our table as "published" are
  86.  *    responded to, even if the address is not our own.
  87.  */
  88. void
  89. arp_input(interface,bp)
  90. struct interface *interface;
  91. struct mbuf *bp;
  92. {
  93.     struct arp_tab *ap;
  94.     struct arp_type *at;
  95.     struct arp arp;
  96.     struct mbuf *htonarp();
  97.  
  98.     arp_stat.recv++;
  99.     if(ntoharp(&arp,&bp) == -1)    /* Convert into host format */
  100.         return;
  101.     if(arp.hardware >= NHWTYPES){
  102.         /* Unknown hardware type, ignore */
  103.         arp_stat.badtype++;
  104.         return;
  105.     }
  106.     at = &arp_type[arp.hardware];
  107.     if(arp.protocol != at->iptype){
  108.         /* Unsupported protocol type, ignore */
  109.         arp_stat.badtype++;
  110.         return;
  111.     }
  112.     if(
  113. #if MAXHWALEN < 255
  114.        uchar(arp.hwalen) > MAXHWALEN ||
  115. #endif
  116.        arp.pralen != sizeof(int32)){
  117.         /* Incorrect protocol addr length (different hw addr lengths
  118.          * are OK since AX.25 addresses can be of variable length)
  119.          */
  120.         arp_stat.badlen++;
  121.         return;
  122.     }
  123.     if(memcmp(arp.shwaddr,at->bdcst,at->hwalen) == 0){
  124.         /* This guy is trying to say he's got the broadcast address! */
  125.         arp_stat.badaddr++;
  126.         return;
  127.     }
  128.     /* If this guy is already in the table, update its entry
  129.      * unless it's a manual entry (noted by the lack of a timer)
  130.      */
  131.     ap = NULLARP;    /* ap plays the role of merge_flag in the spec */
  132.     if((ap = arp_lookup(interface,arp.hardware,arp.sprotaddr)) != NULLARP
  133.      && ap->timer.start != 0){
  134.         ap = arp_add(interface,arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  135.     }
  136.     /* See if we're the address they're looking for */
  137.     if(arp.tprotaddr == ip_addr){
  138.         if(ap == NULLARP)    /* Only if not already in the table */
  139.             arp_add(interface,arp.sprotaddr,arp.hardware,arp.shwaddr,uchar(arp.hwalen),0);
  140.  
  141.         if(arp.opcode == ARP_REQUEST){
  142.             /* Swap sender's and target's (us) hardware and protocol
  143.              * fields, and send the packet back as a reply
  144.              */
  145.             memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  146.             /* Mark the end of the sender's AX.25 address
  147.              * in case he didn't
  148.              */
  149.             if(arp.hardware == ARP_AX25)
  150.                 arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  151.  
  152.             memcpy(arp.shwaddr,interface->hwaddr,at->hwalen);
  153.             arp.tprotaddr = arp.sprotaddr;
  154.             arp.sprotaddr = ip_addr;
  155.             arp.opcode = ARP_REPLY;
  156.             if((bp = htonarp(&arp)) == NULLBUF)
  157.                 return;
  158.  
  159.             if(interface->forw != NULLIF)
  160.                 (*interface->forw->output)(interface->forw,
  161.                  arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  162.             else
  163.                 (*interface->output)(interface,arp.thwaddr,
  164.                  interface->hwaddr,at->arptype,bp);
  165.             arp_stat.inreq++;
  166.         } else {
  167.             arp_stat.replies++;
  168.         }
  169.     } else if(arp.opcode == ARP_REQUEST
  170.         && (ap = arp_lookup(interface,arp.hardware,arp.tprotaddr)) != NULLARP
  171.         && ap->pub){
  172.         /* Otherwise, respond if the guy he's looking for is
  173.          * published in our table.
  174.          */
  175.         memcpy(arp.thwaddr,arp.shwaddr,(int16)uchar(arp.hwalen));
  176.         /* Mark the end of the sender's AX.25 address
  177.          * in case he didn't
  178.          */
  179.         if(arp.hardware == ARP_AX25)
  180.             arp.thwaddr[uchar(arp.hwalen)-1] |= E;
  181.         memcpy(arp.shwaddr,ap->hw_addr,at->hwalen);
  182.         arp.tprotaddr = arp.sprotaddr;
  183.         arp.sprotaddr = ap->ip_addr;
  184.         arp.opcode = ARP_REPLY;
  185.         if((bp = htonarp(&arp)) == NULLBUF)
  186.             return;
  187.         if(interface->forw != NULLIF)
  188.             (*interface->forw->output)(interface->forw,
  189.              arp.thwaddr,interface->forw->hwaddr,at->arptype,bp);
  190.         else
  191.             (*interface->output)(interface,arp.thwaddr,
  192.              interface->hwaddr,at->arptype,bp);
  193.         arp_stat.inreq++;
  194.     }
  195. }
  196. /* Add an IP-addr / hardware-addr pair to the ARP table */
  197. struct arp_tab *
  198. arp_add(interface,ipaddr,hardware,hw_addr,hw_alen,pub)
  199. struct interface *interface; /* Interface */
  200. int32 ipaddr;        /* IP address, host order */
  201. int16 hardware;        /* Hardware type */
  202. char *hw_addr;        /* Hardware address, if known; NULLCHAR otherwise */
  203. int16 hw_alen;        /* Length of hardware address */
  204. int pub;        /* Publish this entry? */
  205. {
  206.     void arp_drop();
  207.     int ip_route();
  208.     struct mbuf *bp,*dequeue();
  209.     register struct arp_tab *ap;
  210.     unsigned hashval,arp_hash();
  211.  
  212.     if((ap = arp_lookup(interface,hardware,ipaddr)) == NULLARP){
  213.         /* New entry */
  214.         if((ap = (struct arp_tab *)calloc(1,sizeof(struct arp_tab))) == NULLARP)
  215.             return NULLARP;
  216.         ap->timer.func = arp_drop;
  217.         ap->timer.arg = (char *)ap;
  218.         ap->interface = interface;
  219.         ap->hardware = hardware;
  220.         ap->ip_addr = ipaddr;
  221.  
  222.         /* Put on head of hash chain */
  223.         hashval = arp_hash(hardware,ipaddr);
  224.         ap->prev = NULLARP;
  225.         ap->next = arp_tab[hashval];
  226.         arp_tab[hashval] = ap;
  227.         if(ap->next != NULLARP){
  228.             ap->next->prev = ap;
  229.         }
  230.     }
  231.     if(hw_addr == NULLCHAR){
  232.         /* Await response */
  233.         ap->state = ARP_PENDING;
  234.         ap->timer.start = SEC2TICK(PENDTIME);
  235.     } else {
  236.         /* Response has come in, update entry and run through queue */
  237.         if(ap->hw_addr != NULLCHAR)
  238.             free(ap->hw_addr);
  239.         if((ap->hw_addr = malloc(hw_alen)) == NULLCHAR){
  240.             free((char *)ap);
  241.             return NULLARP;
  242.         }
  243.         memcpy(ap->hw_addr,hw_addr,hw_alen);
  244.         /* This kludge marks the end of an AX.25 address to allow
  245.          * for optional digipeaters (insert Joan Rivers salute here)
  246.          */
  247.         if(hardware == ARP_AX25)
  248.             ap->hw_addr[hw_alen-1] |= E;
  249.         ap->state = ARP_VALID;
  250.         ap->timer.start = SEC2TICK(ARPLIFE);
  251.         ap->pub = pub;
  252.         while((bp = dequeue(&ap->pending)) != NULLBUF)
  253.             ip_route(bp,0);
  254.     }
  255.     start_timer(&ap->timer);
  256.     return ap;
  257. }
  258.  
  259. /* Remove an entry from the ARP